<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Migrating from Vue 2 | Vue Router</title>
    <meta name="description" content="The official router for Vue.js.">
    <link rel="stylesheet" href="static/css/style.720cf281.css">
    <link rel="modulepreload" href="https://router.vuejs.org/assets/Home.5d2e3154.js">
    <link rel="modulepreload" href="https://router.vuejs.org/assets/ui-custom.78f8f7a5.js">
    <link rel="modulepreload" href="https://router.vuejs.org/assets/ui-custom.823f6de3.js">
    <link rel="modulepreload" href="https://router.vuejs.org/assets/AlgoliaSearchBox.b1511f6a.js">
    <link rel="modulepreload" href="https://router.vuejs.org/assets/app.4a3417cf.js">
    <link rel="modulepreload" href="https://router.vuejs.org/assets/guide_migration_index.md.f1c1eead.lean.js">
    
    <link rel="icon" href="static/picture/logo.png">
  <meta name="wwads-cn-verify" content="7e7757b1e12abcb736ab9a754ffb617a">
  <script src="static/js/thesemetrics@latest.js" async=""></script>
  <meta name="twitter:title" content="Migrating from Vue 2 | Vue Router">
  <meta property="og:title" content="Migrating from Vue 2 | Vue Router">
  </head>
  <body>
    <div id="app"><div class="main-container" data-v-46b24580=""><!----><!--[--><div class="theme"><header class="nav-bar" data-v-675d8756=""><div class="sidebar-button" data-v-675d8756=""><svg class="icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewbox="0 0 448 512"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z" class=""></path></svg></div><a class="nav-bar-title" href="javascript:;" aria-label="Vue Router, back to home" data-v-675d8756="" data-v-4a583abe=""><!----> Vue Router</a><div class="flex-grow" data-v-675d8756=""></div><div class="nav" data-v-675d8756=""><nav class="nav-links" data-v-675d8756="" data-v-eab3edfe=""><!--[--><div class="item" data-v-eab3edfe=""><div class="nav-link" data-v-eab3edfe="" data-v-b8818f8c=""><a class="item active" href="javascript:;" data-v-b8818f8c="">Guide <!----></a></div></div><div class="item" data-v-eab3edfe=""><div class="nav-link" data-v-eab3edfe="" data-v-b8818f8c=""><a class="item" href="javascript:;" data-v-b8818f8c="">API Reference <!----></a></div></div><div class="item" data-v-eab3edfe=""><div class="nav-dropdown-link" data-v-eab3edfe="" data-v-56bf3a3f=""><button class="button" data-v-56bf3a3f=""><span class="button-text" data-v-56bf3a3f="">v4.x</span><span class="right button-arrow" data-v-56bf3a3f=""></span></button><ul class="dialog" data-v-56bf3a3f=""><!--[--><li class="dialog-item" data-v-56bf3a3f=""><div class="nav-dropdown-link-item" data-v-56bf3a3f="" data-v-bbc27490=""><a class="item isExternal" href="javascript:;" target="_blank" rel="noopener noreferrer" data-v-bbc27490=""><span class="arrow" data-v-bbc27490=""></span><span class="text" data-v-bbc27490="">v3.x</span><span class="icon" data-v-bbc27490=""><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15" data-v-bbc27490=""><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></span></a></div></li><!--]--></ul></div></div><div class="item" data-v-eab3edfe=""><div class="nav-link" data-v-eab3edfe="" data-v-b8818f8c=""><a class="item isExternal" href="javascript:;" target="_blank" rel="noopener noreferrer" data-v-b8818f8c="">Changelog <svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15" data-v-b8818f8c=""><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></div></div><!--]--><div class="item" data-v-eab3edfe=""><div class="nav-dropdown-link" data-v-eab3edfe="" data-v-56bf3a3f=""><button class="button" data-v-56bf3a3f=""><span class="button-text" data-v-56bf3a3f="">Languages</span><span class="right button-arrow" data-v-56bf3a3f=""></span></button><ul class="dialog" data-v-56bf3a3f=""><!--[--><li class="dialog-item" data-v-56bf3a3f=""><div class="nav-dropdown-link-item" data-v-56bf3a3f="" data-v-bbc27490=""><a class="item active" href="" data-v-bbc27490=""><span class="arrow" data-v-bbc27490=""></span><span class="text" data-v-bbc27490="">English</span><span class="icon" data-v-bbc27490=""><!----></span></a></div></li><li class="dialog-item" data-v-56bf3a3f=""><div class="nav-dropdown-link-item" data-v-56bf3a3f="" data-v-bbc27490=""><a class="item" href="javascript:;" data-v-bbc27490=""><span class="arrow" data-v-bbc27490=""></span><span class="text" data-v-bbc27490="">中文</span><span class="icon" data-v-bbc27490=""><!----></span></a></div></li><!--]--></ul></div></div><div class="item" data-v-eab3edfe=""><div class="nav-link" data-v-eab3edfe="" data-v-b8818f8c=""><a class="item isExternal" href="javascript:;" target="_blank" rel="noopener noreferrer" data-v-b8818f8c="">GitHub <svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15" data-v-b8818f8c=""><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></div></div></nav></div><!--[--><!--[--><div class="algolia-search-box" id="docsearch"></div><!--]--><!--]--></header><aside class="sidebar" data-v-83e92a68=""><nav class="nav-links nav" data-v-83e92a68="" data-v-eab3edfe=""><!--[--><div class="item" data-v-eab3edfe=""><div class="nav-link" data-v-eab3edfe="" data-v-b8818f8c=""><a class="item active" href="javascript:;" data-v-b8818f8c="">Guide <!----></a></div></div><div class="item" data-v-eab3edfe=""><div class="nav-link" data-v-eab3edfe="" data-v-b8818f8c=""><a class="item" href="javascript:;" data-v-b8818f8c="">API Reference <!----></a></div></div><div class="item" data-v-eab3edfe=""><div class="nav-dropdown-link" data-v-eab3edfe="" data-v-56bf3a3f=""><button class="button" data-v-56bf3a3f=""><span class="button-text" data-v-56bf3a3f="">v4.x</span><span class="right button-arrow" data-v-56bf3a3f=""></span></button><ul class="dialog" data-v-56bf3a3f=""><!--[--><li class="dialog-item" data-v-56bf3a3f=""><div class="nav-dropdown-link-item" data-v-56bf3a3f="" data-v-bbc27490=""><a class="item isExternal" href="javascript:;" target="_blank" rel="noopener noreferrer" data-v-bbc27490=""><span class="arrow" data-v-bbc27490=""></span><span class="text" data-v-bbc27490="">v3.x</span><span class="icon" data-v-bbc27490=""><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15" data-v-bbc27490=""><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></span></a></div></li><!--]--></ul></div></div><div class="item" data-v-eab3edfe=""><div class="nav-link" data-v-eab3edfe="" data-v-b8818f8c=""><a class="item isExternal" href="javascript:;" target="_blank" rel="noopener noreferrer" data-v-b8818f8c="">Changelog <svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15" data-v-b8818f8c=""><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></div></div><!--]--><div class="item" data-v-eab3edfe=""><div class="nav-dropdown-link" data-v-eab3edfe="" data-v-56bf3a3f=""><button class="button" data-v-56bf3a3f=""><span class="button-text" data-v-56bf3a3f="">Languages</span><span class="right button-arrow" data-v-56bf3a3f=""></span></button><ul class="dialog" data-v-56bf3a3f=""><!--[--><li class="dialog-item" data-v-56bf3a3f=""><div class="nav-dropdown-link-item" data-v-56bf3a3f="" data-v-bbc27490=""><a class="item active" href="" data-v-bbc27490=""><span class="arrow" data-v-bbc27490=""></span><span class="text" data-v-bbc27490="">English</span><span class="icon" data-v-bbc27490=""><!----></span></a></div></li><li class="dialog-item" data-v-56bf3a3f=""><div class="nav-dropdown-link-item" data-v-56bf3a3f="" data-v-bbc27490=""><a class="item" href="javascript:;" data-v-bbc27490=""><span class="arrow" data-v-bbc27490=""></span><span class="text" data-v-bbc27490="">中文</span><span class="icon" data-v-bbc27490=""><!----></span></a></div></li><!--]--></ul></div></div><div class="item" data-v-eab3edfe=""><div class="nav-link" data-v-eab3edfe="" data-v-b8818f8c=""><a class="item isExternal" href="javascript:;" target="_blank" rel="noopener noreferrer" data-v-b8818f8c="">GitHub <svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15" data-v-b8818f8c=""><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></div></div></nav><!--[--><!--[--><div class="sponsors sponsors-top" data-v-46b24580=""><span data-v-46b24580="">Platinum Sponsors</span><!--[--><a href="javascript:;" target="_blank" rel="noopener" data-v-46b24580=""><img src="https://posva-sponsors.pages.dev/logos/fincliplogo_black_svg.svg" alt="Finogeeks" data-v-46b24580=""></a><!--]--></div><!--]--><!--]--><ul class="sidebar-links" data-v-83e92a68=""><!--[--><li class="sidebar-link"><a class="sidebar-link-item" href="introduction2.html">Introduction</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="installation1.html">Installation</a><!----></li><li class="sidebar-link"><p class="sidebar-link-item">Essentials</p><ul class="sidebar-links"><li class="sidebar-link"><a class="sidebar-link-item" href="javascript:;">Getting Started</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="dynamic-matching.html">Dynamic Route Matching</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="route-matching-syntax.html">Routes&#39; Matching Syntax</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="nested-routes.html">Nested Routes</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="navigation.html">Programmatic Navigation</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="named-routes.html">Named Routes</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="named-views.html">Named Views</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="redirect-and-alias.html">Redirect and Alias</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="passing-props.html">Passing Props to Route Components</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="history-mode.html">Different History modes</a><!----></li></ul></li><li class="sidebar-link"><p class="sidebar-link-item">Advanced</p><ul class="sidebar-links"><li class="sidebar-link"><a class="sidebar-link-item" href="navigation-guards.html">Navigation guards</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="meta.html">Route Meta Fields</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="data-fetching.html">Data Fetching</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="composition-api1.html">Composition API</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="transitions.html">Transitions</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="scroll-behavior.html">Scroll Behavior</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="lazy-loading.html">Lazy Loading Routes</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="extending-router-link.html">Extending RouterLink</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="navigation-failures.html">Navigation Failures</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="dynamic-routing.html">Dynamic Routing</a><!----></li></ul></li><li class="sidebar-link"><a class="sidebar-link-item active" href="">Migrating from Vue 2</a><ul class="sidebar-links"><li class="sidebar-link"><a class="sidebar-link-item" href="#breaking-changes">Breaking Changes</a><ul class="sidebar-links"><li class="sidebar-link"><a class="sidebar-link-item" href="#new-router-becomes-createrouter">new Router becomes createRouter</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#new-history-option-to-replace-mode">New history option to replace mode</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#moved-the-base-option">Moved the base option</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-the-fallback-option">Removal of the fallback option</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removed-star-or-catch-all-routes">Removed * (star or catch all) routes</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#replaced-onready-with-isready">Replaced onReady with isReady</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#scrollbehavior-changes">scrollBehavior changes</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#router-view-keep-alive-and-transition">&lt;router-view&gt;, &lt;keep-alive&gt;, and &lt;transition&gt;</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-append-prop-in-router-link">Removal of append prop in &lt;router-link&gt;</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-event-and-tag-props-in-router-link">Removal of event and tag props in &lt;router-link&gt;</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-the-exact-prop-in-router-link">Removal of the exact prop in &lt;router-link&gt;</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#navigation-guards-in-mixins-are-ignored">Navigation guards in mixins are ignored</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-router-match-and-changes-to-router-resolve">Removal of router.match and changes to router.resolve</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-router-getmatchedcomponents">Removal of router.getMatchedComponents()</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#all-navigations-are-now-always-asynchronous">All navigations are now always asynchronous</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-router-app">Removal of router.app</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#passing-content-to-route-components-slot">Passing content to route components&#39; &lt;slot&gt;</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-parent-from-route-locations">Removal of parent from route locations</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-pathtoregexpoptions">Removal of pathToRegexpOptions</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#removal-of-unnamed-parameters">Removal of unnamed parameters</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#usage-of-history-state">Usage of history.state</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#routes-option-is-required-in-options">routes option is required in options</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#non-existent-named-routes">Non existent named routes</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#missing-required-params-on-named-routes">Missing required params on named routes</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#named-children-routes-with-an-empty-path-no-longer-appends-a-slash">Named children routes with an empty path no longer appends a slash</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#route-properties-encoding">$route properties Encoding</a><!----></li><li class="sidebar-link"><a class="sidebar-link-item" href="#typescript-changes">TypeScript changes</a><!----></li></ul></li><li class="sidebar-link"><a class="sidebar-link-item" href="#new-features">New Features</a><!----></li></ul></li><!--]--></ul><!--[--><!--[--><div class="sponsors" data-v-46b24580=""><span data-v-46b24580="">Sponsors</span><!--[--><a href="javascript:;" target="_blank" rel="noopener" data-v-46b24580=""><img src="https://posva-sponsors.pages.dev/logos/vuejobs.svg" alt="VueJobs" data-v-46b24580=""></a><!--]--></div><!--]--><!--]--></aside><div class="sidebar-mask"></div><main class="page" data-v-7eddb2c4=""><div class="container" data-v-7eddb2c4=""><!--[--><!--[--><div id="ads-container"><div class="carbon-ads" ref_key="el" data-v-5941b830=""></div></div><!--]--><!--[--><!--]--><!--]--><div style="position:relative;" class="content" data-v-7eddb2c4=""><div><h1 id="migrating-from-vue-2" tabindex="-1">Migrating from Vue 2 <a class="header-anchor" href="#migrating-from-vue-2" aria-hidden="true">#</a></h1><p>Most of Vue Router API has remained unchanged during its rewrite from v3 (for Vue 2) to v4 (for Vue 3) but there are still a few breaking changes that you might encounter while migrating your application. This guide is here to help you understand why these changes happened and how to adapt your application to make it work with Vue Router 4.</p><h2 id="breaking-changes" tabindex="-1">Breaking Changes <a class="header-anchor" href="#breaking-changes" aria-hidden="true">#</a></h2><p>Changes are ordered by their usage. It is therefore recommended to follow this list in order.</p><h3 id="new-router-becomes-createrouter" tabindex="-1">new Router becomes createRouter <a class="header-anchor" href="#new-router-becomes-createrouter" aria-hidden="true">#</a></h3><p>Vue Router is no longer a class but a set of functions. Instead of writing <code>new Router()</code>, you now have to call <code>createRouter</code>:</p><div class="language-js"><pre><code><span class="token comment">// previously was</span>
<span class="token comment">// import Router from &#39;vue-router&#39;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> createRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&#39;vue-router&#39;</span>

<span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token function">createRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><h3 id="new-history-option-to-replace-mode" tabindex="-1">New <code>history</code> option to replace <code>mode</code> <a class="header-anchor" href="#new-history-option-to-replace-mode" aria-hidden="true">#</a></h3><p>The <code>mode: &#39;history&#39;</code> option has been replaced with a more flexible one named <code>history</code>. Depending on which mode you were using, you will have to replace it with the appropriate function:</p><ul><li><code>&quot;history&quot;</code>: <code>createWebHistory()</code></li><li><code>&quot;hash&quot;</code>: <code>createWebHashHistory()</code></li><li><code>&quot;abstract&quot;</code>: <code>createMemoryHistory()</code></li></ul><p>Here is a full snippet:</p><div class="language-js"><pre><code><span class="token keyword">import</span> <span class="token punctuation">{</span> createRouter<span class="token punctuation">,</span> createWebHistory <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&#39;vue-router&#39;</span>
<span class="token comment">// there is also createWebHashHistory and createMemoryHistory</span>

<span class="token function">createRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">history</span><span class="token operator">:</span> <span class="token function">createWebHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token literal-property property">routes</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>On SSR, you need to manually pass the appropriate history:</p><div class="language-js"><pre><code><span class="token comment">// router.js</span>
<span class="token keyword">let</span> history <span class="token operator">=</span> isServer <span class="token operator">?</span> <span class="token function">createMemoryHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">createWebHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">let</span> router <span class="token operator">=</span> <span class="token function">createRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</span> routes<span class="token punctuation">,</span> history <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token comment">// somewhere in your server-entry.js</span>
router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span>url<span class="token punctuation">)</span> <span class="token comment">// request url</span>
router<span class="token punctuation">.</span><span class="token function">isReady</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token comment">// resolve the request</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p><strong>Reason</strong>: enable tree shaking of non used histories as well as implementing custom histories for advanced use cases like native solutions.</p><h3 id="moved-the-base-option" tabindex="-1">Moved the <code>base</code> option <a class="header-anchor" href="#moved-the-base-option" aria-hidden="true">#</a></h3><p>The <code>base</code> option is now passed as the first argument to <code>createWebHistory</code> (and other histories):</p><div class="language-js"><pre><code><span class="token keyword">import</span> <span class="token punctuation">{</span> createRouter<span class="token punctuation">,</span> createWebHistory <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&#39;vue-router&#39;</span>
<span class="token function">createRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">history</span><span class="token operator">:</span> <span class="token function">createWebHistory</span><span class="token punctuation">(</span><span class="token string">&#39;/base-directory/&#39;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token literal-property property">routes</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><h3 id="removal-of-the-fallback-option" tabindex="-1">Removal of the <code>fallback</code> option <a class="header-anchor" href="#removal-of-the-fallback-option" aria-hidden="true">#</a></h3><p>The <code>fallback</code> option is no longer supported when creating the router:</p><div class="language-diff"><pre><code><span class="token deleted-sign deleted"><span class="token prefix deleted">-</span><span class="token line">new VueRouter({
</span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line">createRouter({
</span></span><span class="token deleted-sign deleted"><span class="token prefix deleted">-</span><span class="token line">  fallback: false,
</span></span>// other options...
})
</code></pre></div><p><strong>Reason</strong>: All browsers supported by Vue support the <a href="javascript:;" target="_blank" rel="noopener noreferrer">HTML5 History API</a>, allowing us to avoid hacks around modifying <code>location.hash</code> and directly use <code>history.pushState()</code>.</p><h3 id="removed-star-or-catch-all-routes" tabindex="-1">Removed <code>*</code> (star or catch all) routes <a class="header-anchor" href="#removed-star-or-catch-all-routes" aria-hidden="true">#</a></h3><p>Catch all routes (<code>*</code>, <code>/*</code>) must now be defined using a parameter with a custom regex:</p><div class="language-js"><pre><code><span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token comment">// pathMatch is the name of the param, e.g., going to /not/found yields</span>
  <span class="token comment">// { params: { pathMatch: [&#39;not&#39;, &#39;found&#39;] }}</span>
  <span class="token comment">// this is thanks to the last *, meaning repeated params and it is necessary if you</span>
  <span class="token comment">// plan on directly navigating to the not-found route using its name</span>
  <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">&#39;/:pathMatch(.*)*&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;not-found&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><span class="token operator">:</span> NotFound <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token comment">// if you omit the last `*`, the `/` character in params will be encoded when resolving or pushing</span>
  <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">&#39;/:pathMatch(.*)&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;bad-not-found&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><span class="token operator">:</span> NotFound <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span>
<span class="token comment">// bad example if using named routes:</span>
router<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;bad-not-found&#39;</span><span class="token punctuation">,</span>
  <span class="token literal-property property">params</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">pathMatch</span><span class="token operator">:</span> <span class="token string">&#39;not/found&#39;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>href <span class="token comment">// &#39;/not%2Ffound&#39;</span>
<span class="token comment">// good example:</span>
router<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;not-found&#39;</span><span class="token punctuation">,</span>
  <span class="token literal-property property">params</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">pathMatch</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">&#39;not&#39;</span><span class="token punctuation">,</span> <span class="token string">&#39;found&#39;</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>href <span class="token comment">// &#39;/not/found&#39;</span>
</code></pre></div><div class="tip custom-block"><p class="custom-block-title">TIP</p><p>You don&#39;t need to add the <code>*</code> for repeated params if you don&#39;t plan to directly push to the not found route using its name. If you call <code>router.push(&#39;/not/found/url&#39;)</code>, it will provide the right <code>pathMatch</code> param.</p></div><p><strong>Reason</strong>: Vue Router doesn&#39;t use <code>path-to-regexp</code> anymore, instead it implements its own parsing system that allows route ranking and enables dynamic routing. Since we usually add one single catch-all route per project, there is no big benefit in supporting a special syntax for <code>*</code>. The encoding of params is encoding across routes, without exception to make things easier to predict.</p><h3 id="replaced-onready-with-isready" tabindex="-1">Replaced <code>onReady</code> with <code>isReady</code> <a class="header-anchor" href="#replaced-onready-with-isready" aria-hidden="true">#</a></h3><p>The existing <code>router.onReady()</code> function has been replaced with <code>router.isReady()</code> which doesn&#39;t take any argument and returns a Promise:</p><div class="language-js"><pre><code><span class="token comment">// replace</span>
router<span class="token punctuation">.</span><span class="token function">onReady</span><span class="token punctuation">(</span>onSuccess<span class="token punctuation">,</span> onError<span class="token punctuation">)</span>
<span class="token comment">// with</span>
router<span class="token punctuation">.</span><span class="token function">isReady</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>onSuccess<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span>onError<span class="token punctuation">)</span>
<span class="token comment">// or use await:</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
  <span class="token keyword">await</span> router<span class="token punctuation">.</span><span class="token function">isReady</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token comment">// onSuccess</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// onError</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="scrollbehavior-changes" tabindex="-1"><code>scrollBehavior</code> changes <a class="header-anchor" href="#scrollbehavior-changes" aria-hidden="true">#</a></h3><p>The object returned in <code>scrollBehavior</code> is now similar to <a href="javascript:;" target="_blank" rel="noopener noreferrer"><code>ScrollToOptions</code></a>: <code>x</code> is renamed to <code>left</code> and <code>y</code> is renamed to <code>top</code>. See <a href="javascript:;" target="_blank" rel="noopener noreferrer">RFC</a>.</p><p><strong>Reason</strong>: making the object similar to <code>ScrollToOptions</code> to make it feel more familiar with native JS APIs and potentially enable future new options.</p><h3 id="router-view-keep-alive-and-transition" tabindex="-1"><code>&lt;router-view&gt;</code>, <code>&lt;keep-alive&gt;</code>, and <code>&lt;transition&gt;</code> <a class="header-anchor" href="#router-view-keep-alive-and-transition" aria-hidden="true">#</a></h3><p><code>transition</code> and <code>keep-alive</code> must now be used <strong>inside</strong> of <code>RouterView</code> via the <code>v-slot</code> API:</p><div class="language-vue"><pre><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-view</span> <span class="token attr-name">v-slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>{ Component }<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>transition</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>keep-alive</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>component</span> <span class="token attr-name">:is</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>Component<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>keep-alive</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>transition</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-view</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p><strong>Reason</strong>: This was a necessary change. See the <a href="javascript:;" target="_blank" rel="noopener noreferrer">related RFC</a>.</p><h3 id="removal-of-append-prop-in-router-link" tabindex="-1">Removal of <code>append</code> prop in <code>&lt;router-link&gt;</code> <a class="header-anchor" href="#removal-of-append-prop-in-router-link" aria-hidden="true">#</a></h3><p>The <code>append</code> prop has been removed from <code>&lt;router-link&gt;</code>. You can manually concatenate the value to an existing <code>path</code> instead:</p><div class="language-html"><pre><code>replace
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-link</span> <span class="token attr-name">to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>child-route<span class="token punctuation">&quot;</span></span> <span class="token attr-name">append</span><span class="token punctuation">&gt;</span></span>to relative child<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-link</span><span class="token punctuation">&gt;</span></span>
with
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-link</span> <span class="token attr-name">:to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>append($route.path, <span class="token punctuation">&#39;</span>child-route<span class="token punctuation">&#39;</span>)<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  to relative child
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-link</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>You must define a global <code>append</code> function on your <em>App</em> instance:</p><div class="language-js"><pre><code>app<span class="token punctuation">.</span>config<span class="token punctuation">.</span>globalProperties<span class="token punctuation">.</span><span class="token function-variable function">append</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">path<span class="token punctuation">,</span> pathToAppend</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span>
  path <span class="token operator">+</span> <span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">&#39;/&#39;</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">&#39;&#39;</span> <span class="token operator">:</span> <span class="token string">&#39;/&#39;</span><span class="token punctuation">)</span> <span class="token operator">+</span> pathToAppend
</code></pre></div><p><strong>Reason</strong>: <code>append</code> wasn&#39;t used very often, is easy to replicate in user land.</p><h3 id="removal-of-event-and-tag-props-in-router-link" tabindex="-1">Removal of <code>event</code> and <code>tag</code> props in <code>&lt;router-link&gt;</code> <a class="header-anchor" href="#removal-of-event-and-tag-props-in-router-link" aria-hidden="true">#</a></h3><p>Both <code>event</code>, and <code>tag</code> props have been removed from <code>&lt;router-link&gt;</code>. You can use the <a href="javascript:;"><code>v-slot</code> API</a> to fully customize <code>&lt;router-link&gt;</code>:</p><div class="language-html"><pre><code>replace
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-link</span> <span class="token attr-name">to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>/about<span class="token punctuation">&quot;</span></span> <span class="token attr-name">tag</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>span<span class="token punctuation">&quot;</span></span> <span class="token attr-name">event</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>dblclick<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>About Us<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-link</span><span class="token punctuation">&gt;</span></span>
with
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-link</span> <span class="token attr-name">to</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>/about<span class="token punctuation">&quot;</span></span> <span class="token attr-name">custom</span> <span class="token attr-name">v-slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>{ navigate }<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>navigate<span class="token punctuation">&quot;</span></span> <span class="token attr-name">@keypress.enter</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>navigate<span class="token punctuation">&quot;</span></span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>link<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>About Us<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-link</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p><strong>Reason</strong>: These props were often used together to use something different from an <code>&lt;a&gt;</code> tag but were introduced before the <code>v-slot</code> API and are not used enough to justify adding to the bundle size for everybody.</p><h3 id="removal-of-the-exact-prop-in-router-link" tabindex="-1">Removal of the <code>exact</code> prop in <code>&lt;router-link&gt;</code> <a class="header-anchor" href="#removal-of-the-exact-prop-in-router-link" aria-hidden="true">#</a></h3><p>The <code>exact</code> prop has been removed because the caveat it was fixing is no longer present so you should be able to safely remove it. There are however two things you should be aware of:</p><ul><li>Routes are now active based on the route records they represent instead of the generated route location objects and their <code>path</code>, <code>query</code>, and <code>hash</code> properties</li><li>Only the <code>path</code> section is matched, <code>query</code>, and <code>hash</code> aren&#39;t taken into account anymore</li></ul><p>If you wish to customize this behavior, e.g. take into account the <code>hash</code> section, you should use the <a href="javascript:;" target="_blank" rel="noopener noreferrer"><code>v-slot</code> API</a> to extend <code>&lt;router-link&gt;</code>.</p><p><strong>Reason</strong>: See the <a href="javascript:;" target="_blank" rel="noopener noreferrer">RFC about active matching</a> changes for more details.</p><h3 id="navigation-guards-in-mixins-are-ignored" tabindex="-1">Navigation guards in mixins are ignored <a class="header-anchor" href="#navigation-guards-in-mixins-are-ignored" aria-hidden="true">#</a></h3><p>At the moment navigation guards in mixins are not supported. You can track its support at <a href="javascript:;" target="_blank" rel="noopener noreferrer">vue-router#454</a>.</p><h3 id="removal-of-router-match-and-changes-to-router-resolve" tabindex="-1">Removal of <code>router.match</code> and changes to <code>router.resolve</code> <a class="header-anchor" href="#removal-of-router-match-and-changes-to-router-resolve" aria-hidden="true">#</a></h3><p>Both <code>router.match</code>, and <code>router.resolve</code> have been merged together into <code>router.resolve</code> with a slightly different signature. <a href="javascript:;">Refer to the API</a> for more details.</p><p><strong>Reason</strong>: Uniting multiple methods that were used for the same purpose.</p><h3 id="removal-of-router-getmatchedcomponents" tabindex="-1">Removal of <code>router.getMatchedComponents()</code> <a class="header-anchor" href="#removal-of-router-getmatchedcomponents" aria-hidden="true">#</a></h3><p>The method <code>router.getMatchedComponents</code> is now removed as matched components can be retrieved from <code>router.currentRoute.value.matched</code>:</p><div class="language-js"><pre><code>router<span class="token punctuation">.</span>currentRoute<span class="token punctuation">.</span>value<span class="token punctuation">.</span>matched<span class="token punctuation">.</span><span class="token function">flatMap</span><span class="token punctuation">(</span><span class="token parameter">record</span> <span class="token operator">=&gt;</span>
  Object<span class="token punctuation">.</span><span class="token function">values</span><span class="token punctuation">(</span>record<span class="token punctuation">.</span>components<span class="token punctuation">)</span>
<span class="token punctuation">)</span>
</code></pre></div><p><strong>Reason</strong>: This method was only used during SSR and is a one liner that can be done by the user.</p><h3 id="all-navigations-are-now-always-asynchronous" tabindex="-1"><strong>All</strong> navigations are now always asynchronous <a class="header-anchor" href="#all-navigations-are-now-always-asynchronous" aria-hidden="true">#</a></h3><p>All navigations, including the first one, are now asynchronous, meaning that, if you use a <code>transition</code>, you may need to wait for the router to be <em>ready</em> before mounting the app:</p><div class="language-js"><pre><code>app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>router<span class="token punctuation">)</span>
<span class="token comment">// Note: on Server Side, you need to manually push the initial location</span>
router<span class="token punctuation">.</span><span class="token function">isReady</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> app<span class="token punctuation">.</span><span class="token function">mount</span><span class="token punctuation">(</span><span class="token string">&#39;#app&#39;</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div><p>Otherwise there will be an initial transition as if you provided the <code>appear</code> prop to <code>transition</code> because the router displays its initial location (nothing) and then displays the first location.</p><p>Note that <strong>if you have navigation guards upon the initial navigation</strong>, you might not want to block the app render until they are resolved unless you are doing Server Side Rendering. In this scenario, not waiting the router to be ready to mount the app would yield the same result as in Vue 2.</p><h3 id="removal-of-router-app" tabindex="-1">Removal of <code>router.app</code> <a class="header-anchor" href="#removal-of-router-app" aria-hidden="true">#</a></h3><p><code>router.app</code> used to represent the last root component (Vue instance) that injected the router. Vue Router can now be safely used by multiple Vue applications at the same time. You can still add it when using the router:</p><div class="language-js"><pre><code>app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>router<span class="token punctuation">)</span>
router<span class="token punctuation">.</span>app <span class="token operator">=</span> app
</code></pre></div><p>You can also extend the TypeScript definition of the <code>Router</code> interface to add the <code>app</code> property.</p><p><strong>Reason</strong>: Vue 3 applications do not exist in Vue 2 and now we properly support multiple applications using the same Router instance, so having an <code>app</code> property would have been misleading because it would have been the application instead of the root instance.</p><h3 id="passing-content-to-route-components-slot" tabindex="-1">Passing content to route components&#39; <code>&lt;slot&gt;</code> <a class="header-anchor" href="#passing-content-to-route-components-slot" aria-hidden="true">#</a></h3><p>Before you could directly pass a template to be rendered by a route components&#39; <code>&lt;slot&gt;</code> by nesting it under a <code>&lt;router-view&gt;</code> component:</p><div class="language-html"><pre><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-view</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>In Vue Router 3, I render inside the route component<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-view</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>Because of the introduction of the <code>v-slot</code> api for <code>&lt;router-view&gt;</code>, you must pass it to the <code>&lt;component&gt;</code> using the <code>v-slot</code> API:</p><div class="language-html"><pre><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>router-view</span> <span class="token attr-name">v-slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>{ Component }<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>component</span> <span class="token attr-name">:is</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>Component<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>In Vue Router 3, I render inside the route component<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>component</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>router-view</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><h3 id="removal-of-parent-from-route-locations" tabindex="-1">Removal of <code>parent</code> from route locations <a class="header-anchor" href="#removal-of-parent-from-route-locations" aria-hidden="true">#</a></h3><p>The <code>parent</code> property has been removed from normalized route locations (<code>this.$route</code> and object returned by <code>router.resolve</code>). You can still access it via the <code>matched</code> array:</p><div class="language-js"><pre><code><span class="token keyword">const</span> parent <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$route<span class="token punctuation">.</span>matched<span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">.</span>$route<span class="token punctuation">.</span>matched<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">]</span>
</code></pre></div><p><strong>Reason</strong>: Having <code>parent</code> and <code>children</code> creates unnecessary circular references while the properties could be retrieved already through <code>matched</code>.</p><h3 id="removal-of-pathtoregexpoptions" tabindex="-1">Removal of <code>pathToRegexpOptions</code> <a class="header-anchor" href="#removal-of-pathtoregexpoptions" aria-hidden="true">#</a></h3><p>The <code>pathToRegexpOptions</code> and <code>caseSensitive</code> properties of route records have been replaced with <code>sensitive</code> and <code>strict</code> options for <code>createRouter()</code>. They can now also be directly passed when creating the router with <code>createRouter()</code>. Any other option specific to <code>path-to-regexp</code> has been removed as <code>path-to-regexp</code> is no longer used to parse paths.</p><h3 id="removal-of-unnamed-parameters" tabindex="-1">Removal of unnamed parameters <a class="header-anchor" href="#removal-of-unnamed-parameters" aria-hidden="true">#</a></h3><p>Due to the removal of <code>path-to-regexp</code>, unnamed parameters are no longer supported:</p><ul><li><code>/foo(/foo)?/suffix</code> becomes <code>/foo/:_(foo)?/suffix</code></li><li><code>/foo(foo)?</code> becomes <code>/foo:_(foo)?</code></li><li><code>/foo/(.*)</code> becomes <code>/foo/:_(.*)</code></li></ul><div class="tip custom-block"><p class="custom-block-title">TIP</p><p>Note you can use any name instead of <code>_</code> for the param. The point is to provide one.</p></div><h3 id="usage-of-history-state" tabindex="-1">Usage of <code>history.state</code> <a class="header-anchor" href="#usage-of-history-state" aria-hidden="true">#</a></h3><p>Vue Router saves information on the <code>history.state</code>. If you have any code manually calling <code>history.pushState()</code>, you should likely avoid it or refactor it with a regular <code>router.push()</code> and a <code>history.replaceState()</code>:</p><div class="language-js"><pre><code><span class="token comment">// replace</span>
history<span class="token punctuation">.</span><span class="token function">pushState</span><span class="token punctuation">(</span>myState<span class="token punctuation">,</span> <span class="token string">&#39;&#39;</span><span class="token punctuation">,</span> url<span class="token punctuation">)</span>
<span class="token comment">// with</span>
<span class="token keyword">await</span> router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span>
history<span class="token punctuation">.</span><span class="token function">replaceState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token operator">...</span>history<span class="token punctuation">.</span>state<span class="token punctuation">,</span> <span class="token operator">...</span>myState <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">&#39;&#39;</span><span class="token punctuation">)</span>
</code></pre></div><p>Similarly, if you were calling <code>history.replaceState()</code> without preserving the current state, you will need to pass the current <code>history.state</code>:</p><div class="language-js"><pre><code><span class="token comment">// replace</span>
history<span class="token punctuation">.</span><span class="token function">replaceState</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">&#39;&#39;</span><span class="token punctuation">,</span> url<span class="token punctuation">)</span>
<span class="token comment">// with</span>
history<span class="token punctuation">.</span><span class="token function">replaceState</span><span class="token punctuation">(</span>history<span class="token punctuation">.</span>state<span class="token punctuation">,</span> <span class="token string">&#39;&#39;</span><span class="token punctuation">,</span> url<span class="token punctuation">)</span>
</code></pre></div><p><strong>Reason</strong>: We use the history state to save information about the navigation like the scroll position, previous location, etc.</p><h3 id="routes-option-is-required-in-options" tabindex="-1"><code>routes</code> option is required in <code>options</code> <a class="header-anchor" href="#routes-option-is-required-in-options" aria-hidden="true">#</a></h3><p>The property <code>routes</code> is now required in <code>options</code>.</p><div class="language-js"><pre><code><span class="token function">createRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">routes</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p><strong>Reason</strong>: The router is designed to be created with routes even though you can add them later on. You need at least one route in most scenarios and this is written once per app in general.</p><h3 id="non-existent-named-routes" tabindex="-1">Non existent named routes <a class="header-anchor" href="#non-existent-named-routes" aria-hidden="true">#</a></h3><p>Pushing or resolving a non existent named route throws an error:</p><div class="language-js"><pre><code><span class="token comment">// Oops, we made a typo in name</span>
router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;homee&#39;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// throws</span>
router<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;homee&#39;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// throws</span>
</code></pre></div><p><strong>Reason</strong>: Previously, the router would navigate to <code>/</code> but display nothing (instead of the home page). Throwing an error makes more sense because we cannot produce a valid URL to navigate to.</p><h3 id="missing-required-params-on-named-routes" tabindex="-1">Missing required <code>params</code> on named routes <a class="header-anchor" href="#missing-required-params-on-named-routes" aria-hidden="true">#</a></h3><p>Pushing or resolving a named route without its required params will throw an error:</p><div class="language-js"><pre><code><span class="token comment">// given the following route:</span>
<span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">&#39;/users/:id&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;user&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><span class="token operator">:</span> UserDetails <span class="token punctuation">}</span><span class="token punctuation">]</span>

<span class="token comment">// Missing the `id` param will fail</span>
router<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;user&#39;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
router<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;user&#39;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p><strong>Reason</strong>: Same as above.</p><h3 id="named-children-routes-with-an-empty-path-no-longer-appends-a-slash" tabindex="-1">Named children routes with an empty <code>path</code> no longer appends a slash <a class="header-anchor" href="#named-children-routes-with-an-empty-path-no-longer-appends-a-slash" aria-hidden="true">#</a></h3><p>Given any nested named route with an empty <code>path</code>:</p><div class="language-js"><pre><code><span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">&#39;/dashboard&#39;</span><span class="token punctuation">,</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;dashboard-parent&#39;</span><span class="token punctuation">,</span>
    <span class="token literal-property property">component</span><span class="token operator">:</span> DashboardParent<span class="token punctuation">,</span>
    <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">&#39;&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;dashboard&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><span class="token operator">:</span> DashboardDefault <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">&#39;settings&#39;</span><span class="token punctuation">,</span>
        <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;dashboard-settings&#39;</span><span class="token punctuation">,</span>
        <span class="token literal-property property">component</span><span class="token operator">:</span> DashboardSettings<span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span>
</code></pre></div><p>Navigating or resolving to the named route <code>dashboard</code> will now produce a URL <strong>without a trailing slash</strong>:</p><div class="language-js"><pre><code>router<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&#39;dashboard&#39;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>href <span class="token comment">// &#39;/dashboard&#39;</span>
</code></pre></div><p>This has an important side effect about children <code>redirect</code> records like these:</p><div class="language-js"><pre><code><span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">&#39;/parent&#39;</span><span class="token punctuation">,</span>
    <span class="token literal-property property">component</span><span class="token operator">:</span> Parent<span class="token punctuation">,</span>
    <span class="token literal-property property">children</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token comment">// this would now redirect to `/home` instead of `/parent/home`</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">&#39;&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">redirect</span><span class="token operator">:</span> <span class="token string">&#39;home&#39;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">&#39;home&#39;</span><span class="token punctuation">,</span> <span class="token literal-property property">component</span><span class="token operator">:</span> Home <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span>
</code></pre></div><p>Note this will work if <code>path</code> was <code>/parent/</code> as the relative location <code>home</code> to <code>/parent/</code> is indeed <code>/parent/home</code> but the relative location of <code>home</code> to <code>/parent</code> is <code>/home</code>.</p><p><strong>Reason</strong>: This is to make trailing slash behavior consistent: by default all routes allow a trailing slash. It can be disabled by using the <code>strict</code> option and manually appending (or not) a slash to the routes.</p><h3 id="route-properties-encoding" tabindex="-1"><code>$route</code> properties Encoding <a class="header-anchor" href="#route-properties-encoding" aria-hidden="true">#</a></h3><p>Decoded values in <code>params</code>, <code>query</code>, and <code>hash</code> are now consistent no matter where the navigation is initiated (older browsers will still produce unencoded <code>path</code> and <code>fullPath</code>). The initial navigation should yield the same results as in-app navigations.</p><p>Given any <a href="javascript:;">normalized route location</a>:</p><ul><li>Values in <code>path</code>, <code>fullPath</code> are not decoded anymore. They will appear as provided by the browser (most browsers provide them encoded). e.g. directly writing on the address bar <code>https://example.com/hello world</code> will yield the encoded version: <code>https://example.com/hello%20world</code> and both <code>path</code> and <code>fullPath</code> will be <code>/hello%20world</code>.</li><li><code>hash</code> is now decoded, that way it can be copied over: <code>router.push({ hash: $route.hash })</code> and be used directly in <a href="javascript:;">scrollBehavior</a>&#39;s <code>el</code> option.</li><li>When using <code>push</code>, <code>resolve</code>, and <code>replace</code> and providing a <code>string</code> location or a <code>path</code> property in an object, <strong>it must be encoded</strong> (like in the previous version). On the other hand, <code>params</code>, <code>query</code> and <code>hash</code> must be provided in its unencoded version.</li><li>The slash character (<code>/</code>) is now properly decoded inside <code>params</code> while still producing an encoded version on the URL: <code>%2F</code>.</li></ul><p><strong>Reason</strong>: This allows to easily copy existing properties of a location when calling <code>router.push()</code> and <code>router.resolve()</code>, and make the resulting route location consistent across browsers. <code>router.push()</code> is now idempotent, meaning that calling <code>router.push(route.fullPath)</code>, <code>router.push({ hash: route.hash })</code>, <code>router.push({ query: route.query })</code>, and <code>router.push({ params: route.params })</code> will not create extra encoding.</p><h3 id="typescript-changes" tabindex="-1">TypeScript changes <a class="header-anchor" href="#typescript-changes" aria-hidden="true">#</a></h3><p>To make typings more consistent and expressive, some types have been renamed:</p><table><thead><tr><th><code>vue-router@3</code></th><th><code>vue-router@4</code></th></tr></thead><tbody><tr><td>RouteConfig</td><td>RouteRecordRaw</td></tr><tr><td>Location</td><td>RouteLocation</td></tr><tr><td>Route</td><td>RouteLocationNormalized</td></tr></tbody></table><h2 id="new-features" tabindex="-1">New Features <a class="header-anchor" href="#new-features" aria-hidden="true">#</a></h2><p>Some of new features to keep an eye on in Vue Router 4 include:</p><ul><li><a href="dynamic-routing.html">Dynamic Routing</a></li><li><a href="composition-api1.html">Composition API</a></li></ul></div></div><footer class="page-footer" data-v-7eddb2c4="" data-v-fb8d84c6=""><div class="edit" data-v-fb8d84c6=""><div class="edit-link" data-v-fb8d84c6="" data-v-1ed99556=""><a class="link" href="javascript:;" target="_blank" rel="noopener noreferrer" data-v-1ed99556="">Suggest changes to this page <svg class="icon outbound icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15" data-v-1ed99556=""><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></div></div><div class="updated" data-v-fb8d84c6=""><!----></div></footer><div class="next-and-prev-link" data-v-7eddb2c4="" data-v-38ede35f=""><div class="container" data-v-38ede35f=""><div class="prev" data-v-38ede35f=""><a class="link" href="javascript:;" data-v-38ede35f=""><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="icon icon-prev" data-v-38ede35f=""><path d="M19,11H7.4l5.3-5.3c0.4-0.4,0.4-1,0-1.4s-1-0.4-1.4,0l-7,7c-0.1,0.1-0.2,0.2-0.2,0.3c-0.1,0.2-0.1,0.5,0,0.8c0.1,0.1,0.1,0.2,0.2,0.3l7,7c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3c0.4-0.4,0.4-1,0-1.4L7.4,13H19c0.6,0,1-0.4,1-1S19.6,11,19,11z"></path></svg><span class="text" data-v-38ede35f="">Dynamic Routing</span></a></div><div class="next" data-v-38ede35f=""><!----></div></div></div><!--[--><!--[--><!--]--><!--[--><div class="buy-sell-ads" data-v-4ce5ad17=""><div class="bsa-cpc" data-v-4ce5ad17=""></div></div><!--]--><!--]--></div></main></div><!----><!--]--></div></div>
    <script>__VP_HASH_MAP__ = JSON.parse("{\"api_index.md\":\"321240c3\",\"guide_advanced_composition-api.md\":\"68a790ce\",\"guide_advanced_data-fetching.md\":\"370bc89e\",\"guide_advanced_dynamic-routing.md\":\"f79d5ab5\",\"guide_advanced_extending-router-link.md\":\"b5cf395a\",\"guide_advanced_lazy-loading.md\":\"7a352201\",\"guide_advanced_meta.md\":\"5a4590ab\",\"guide_advanced_navigation-failures.md\":\"343e3632\",\"guide_advanced_navigation-guards.md\":\"73b500ce\",\"guide_advanced_scroll-behavior.md\":\"60e3ea87\",\"guide_advanced_transitions.md\":\"9784e7ac\",\"guide_essentials_dynamic-matching.md\":\"18d86148\",\"guide_essentials_history-mode.md\":\"59a2bcce\",\"guide_essentials_named-routes.md\":\"f89ffec5\",\"guide_essentials_named-views.md\":\"41a2008e\",\"guide_essentials_navigation.md\":\"80b153b7\",\"guide_essentials_nested-routes.md\":\"ba58046f\",\"guide_essentials_passing-props.md\":\"bcc923d9\",\"guide_essentials_redirect-and-alias.md\":\"17e6ff8d\",\"guide_essentials_route-matching-syntax.md\":\"dec0fed1\",\"guide_index.md\":\"b96b8b52\",\"guide_migration_index.md\":\"f1c1eead\",\"index.md\":\"af883fea\",\"installation.md\":\"62f300a6\",\"introduction.md\":\"7557a17f\",\"zh_api_index.md\":\"9f7c32af\",\"zh_guide_advanced_composition-api.md\":\"a9ae8936\",\"zh_guide_advanced_data-fetching.md\":\"3402d49f\",\"zh_guide_advanced_dynamic-routing.md\":\"519d3549\",\"zh_guide_advanced_extending-router-link.md\":\"9ac39d5c\",\"zh_guide_advanced_lazy-loading.md\":\"4f7d5f99\",\"zh_guide_advanced_meta.md\":\"b231c4a4\",\"zh_guide_advanced_navigation-failures.md\":\"5e332799\",\"zh_guide_advanced_navigation-guards.md\":\"95378824\",\"zh_guide_advanced_scroll-behavior.md\":\"5a120e17\",\"zh_guide_advanced_transitions.md\":\"b1d10912\",\"zh_guide_essentials_dynamic-matching.md\":\"a2fdd595\",\"zh_guide_essentials_history-mode.md\":\"12d3427d\",\"zh_guide_essentials_named-routes.md\":\"7d1cfb92\",\"zh_guide_essentials_named-views.md\":\"26d1c4bb\",\"zh_guide_essentials_navigation.md\":\"80d9c078\",\"zh_guide_essentials_nested-routes.md\":\"db791098\",\"zh_guide_essentials_passing-props.md\":\"01c7eddf\",\"zh_guide_essentials_redirect-and-alias.md\":\"1d28625c\",\"zh_guide_essentials_route-matching-syntax.md\":\"d0f00217\",\"zh_guide_index.md\":\"522bf3e7\",\"zh_guide_migration_index.md\":\"d9210e4d\",\"zh_index.md\":\"3945a14c\",\"zh_installation.md\":\"f591290e\",\"zh_introduction.md\":\"a27a7262\"}")</script>
    <script type="module" async="" src="static/js/app.4a3417cf.js"></script>
    
  </body>
</html>